/*
 *  SnpCheckOutStory.cpp
 *  AMPlugin
 *
 *  Created by Vu Tiet on 6/18/12.
 *  Copyright 2012 __MyCompanyName__. All rights reserved.
 *
 */

#include "VCPlugInHeaders.h"

// Interface includes:
#include "AMPCAlert.h"
#include "ITextTarget.h"
#include "IIDMLComponentName.h"
#include "ISpreadList.h"
#include "ISnippetImport.h"
#include "IControlView.h"
#include "IGraphicFrameData.h"
#include "PageItemScrapID.h" // kDeleteCmdBoss
#include "IPageItemTypeUtils.h"

// General includes:
#include "SDKFileHelper.h"
#include "StreamUtil.h"
#include "LocaleSetting.h"

// SDK includes:
#include "SDKLayoutHelper.h"

// Framework includes:
#include "AMPID.h"
#include "ISnpRunnableContext.h"
#include "SnpRunnable.h"
#include "ISnipRunParameterUtils.h"
#include "SnpTextModelHelper.h"
#if __INTEL_COMPILER || MACINTOSH
#include "K2Vector.tpp"
#endif

#include "StringUtils.h"
#include "AMGlobal.h"
#include "HTTPRequestHelper.h"
#include "AMPLogCenter.h"
#include "AMPLogDataRecord.h"
#include "ISelectionManager.h"
#include "IStoryList.h"
#include "ISelectionUtils.h"
#include "ITextSelectionSuite.h"
#include "K2Vector.tpp" // For NodeIDList to compile
#include "IPalettePanelUtils.h"
#include "AMPIconFrameUpdate.h"
#include <iostream>
using namespace std;

class SnpCheckOutStory
	{
	public:
		
		/** Constructor.
		 */
		SnpCheckOutStory() {}
		
		/** Destructor
		 */
		virtual ~SnpCheckOutStory() {}
		
		
		/**	Import a snippet as a child of a specified spread
		 @param documentUIDRef specifies document of interest
		 @param snippetFile 
		 @param whichSpread spread index, zero based, within spreadlist (ISpreadList)
		 @return ErrorCode kSuccess on success, other ErrorCode otherwise 
		 */
		ErrorCode ImportToSpreadElement(const UIDRef& documentUIDRef, const IDFile& snippetFile, int32 whichSpread=0);
		
		/**	Import as child of given scripting DOM element, IDOMElement
		 @param domElementUIDRef specifies document of interest
		 @param snippetFile 
		 @return ErrorCode kSuccess on success, other ErrorCode otherwise 
		 */
		ErrorCode ImportToElement(const UIDRef& domElementUIDRef, const IDFile& snippetFile);
		
		
		/** Place the file in a frame and get content.
		 @param layoutControlData
		 @param snippetFile
		 @return content of placed file.
		 */
//		WideString SnpCheckOutStory::textInImportedFile(ILayoutControlData* layoutControlData, const IDFile& snippetFile);
		
		/** Return the range of text displayed by the given text frame.
		 @param mcf
		 @return the range of text displayed by the given frame.
		 */
		InDesign::TextRange	GetTextFrameTextRange(IMultiColumnTextFrame* mcf);
		
		
		/** Return string containing the text displayed in the given text frame.
		 @param mcf specifies the frame whose text is wanted.
		 @return string containing the text displayed in the given text frame.
		 */
		WideString GetWideStringFromTextFrame(IMultiColumnTextFrame* mcf);
		
		/** Return UID of the multi-column item (kMultiColumnItemBoss) associated with
		 the given text frame, kInvalidUID if none.
		 @param graphicFrameUIDRef reference to the text frame's kSplineItemBoss object.
		 @return UID of the multi-column item (kMultiColumnItemBoss) associated with
		 the given text frame, kInvalidUID if none.
		 */
		UID	 GetTextContentUID(const UIDRef& graphicFrameUIDRef);
		
		/** Copy all of the source story content to the destination story.
		 @param sourceStory UIDRef of story from which to copy content.
		 @param destStory UIDRef of story to which content is to be copied.
		 @return kSuccess on success, some other ErrorCode otherwise.
		 */
		ErrorCode CopyAll(const UIDRef& sourceStory, const UIDRef& destStory);
		
		/** Call SnpTextModelHelper::ProcessCopyStoryRangeCmd to copy a given range of text from the
		 source story to the destination story. 
		 @param sourceStory UIDRef of story from which to copy content
		 @param sourceStart index of text to be copied
		 @param sourceLength amount of text to be copied
		 @param destStory UIDRef of story to which content is to be copied
		 @param destStart index where text to be copied
		 @param destLength 0 to insert text in destination story, >0 to replace
		 @precondition 0 <= sourceStart < ITextModel::GetPrimaryStoryThreadSpan() for sourceStory
		 @precondition 1 <= sourceLength <= ITextModel::GetPrimaryStoryThreadSpan() for sourceStory
		 @precondition 0 <= destStart < ITextModel::GetPrimaryStoryThreadSpan() for destStory
		 @precondition 0 <= destLength <= ITextModel::GetPrimaryStoryThreadSpan() for destStory
		 @return kSuccess on success, some other ErrorCode otherwise.
		 @see kCopyStoryRangeCmdBoss
		 @see ITextUtils for wrapper methods.
		 */
		ErrorCode ProcessCopyStoryRangeCmd
		(
		 const UIDRef& sourceStory, 
		 TextIndex sourceStart, 
		 int32 sourceLength, 
		 const UIDRef& destStory,
		 TextIndex destStart, 
		 int32 destLength
		 );
		
				
		bool16 IsTextFrame(const UIDRef& graphicFrameUIDRef);
		
		ErrorCode ImportICMLFileToStory(ILayoutControlData* layoutControlData, const IDFile& icmlFile, UIDRef& destStory);
		
		ErrorCode ReplaceStoryByICMLs(string _attribute, string storyID, string storySessionID);
		
		ErrorCode PutICMLFileToStory(const IDFile& icmlFile, UIDRef& destStory);
	};


/*
 */
ErrorCode SnpCheckOutStory::ImportToSpreadElement(const UIDRef& documentUIDRef, const IDFile& snippetFile, 
														int32 whichSpread)
{
	ErrorCode result = kFailure;
	do {
		
		// + precondition
		InterfacePtr<IDocument> document(documentUIDRef, UseDefaultIID());
		ASSERT(document);
		if(!document) {
			break;
		}
		SDKFileHelper targetFileHelper(snippetFile);
		ASSERT(targetFileHelper.IsExisting());
		// -preconditions
		InterfacePtr<ISpreadList> spreadList(document, UseDefaultIID());
		ASSERT(spreadList);
		if(!spreadList) {
			break;
		}
		
		int32 spreadCount = spreadList->GetSpreadCount();
		cout << "spreadList count: " << spreadCount << endl;
		
		UIDRef spreadUIDRef(documentUIDRef.GetDataBase(), spreadList->GetNthSpreadUID(whichSpread));
		result = this->ImportToElement(spreadUIDRef, snippetFile);
		
		result = kSuccess;
	} while(false);
	return result;
}

/*
 */
ErrorCode SnpCheckOutStory::ImportToElement(const UIDRef& domElementUIDRef, const IDFile& snippetFile)
{
	ErrorCode result = kFailure;
	do {
		
		InterfacePtr<IPMStream> stream(static_cast<IPMStream*>(StreamUtil::CreateFileStreamRead(snippetFile, kOpenIn)));
		ASSERT(stream);
		if(!stream) {
			break;
		}
		
		InterfacePtr<IDOMElement> xmlFragment(domElementUIDRef, UseDefaultIID());
		ASSERT(xmlFragment);
		if(!xmlFragment) {
			break;
		}
		result = Utils<ISnippetImport>()->ImportFromStream(stream, xmlFragment);
	} while(false);
	return result;
}


/*
 */
#if 0
WideString SnpCheckOutStory::textInImportedFile(ILayoutControlData* layoutControlData, const IDFile& snippetFile)
{
	WideString result("");
	SDKLayoutHelper layoutHelper;
	do {
		
		/*
		// Choose a file to be placed.
		Utils<ISnipRunParameterUtils> parameterUtils;
		SDKFilePlaceChooser fileChooser; //change to ISnipRunParameterUtils once it supports IDFile parameters
		fileChooser.ShowDialog();
		if (!fileChooser.IsChosen()) {
			break;
		}
		 */
		
		// Assume we failed till we know we succeeded.
		//result = kFailure;
		
		// Parent the frame on the active spread layer.
		InterfacePtr<IHierarchy> activeSpreadLayerHierarchy(layoutControlData->QueryActiveLayer());
		ASSERT(activeSpreadLayerHierarchy != nil);
		if (activeSpreadLayerHierarchy == nil) {
			break;
		}
		UIDRef parentUIDRef = ::GetUIDRef(activeSpreadLayerHierarchy);
		
		// Transform the bounds of the frame from page co-ordinates
		// into the parent co-ordinates, i.e. the spread.
		ASSERT(layoutControlData->GetPage() != kInvalidUID);
		if (layoutControlData->GetPage() == kInvalidUID) {
			break;
		}
		UIDRef pageUIDRef(parentUIDRef.GetDataBase(), layoutControlData->GetPage());
		PMRect boundsInPageCoords(0,0,2000,2000); // hard wire for now.
		PMRect boundsInParentCoords = layoutHelper.PageToSpread(pageUIDRef, boundsInPageCoords);
		
		// Place the file in a frame.
		/*
		UIFlags uiFlags = K2::kMinimalUI;
		if (fileChooser.GetShowFilterPrefs()) {
			uiFlags = K2::kFullUI;
		}
		*/
		UIDRef frameRef = layoutHelper.PlaceFileInFrame(snippetFile,
														parentUIDRef,
														boundsInParentCoords,
														kMinimalUI, 
														TRUE,
														TRUE, 
														FALSE);
		
		// TODO add code that looks at SDKFilePlaceChooser::GetReplaceSelectedItem
		// and replaces the content of the frame indicated by selectedItemRef.
		
		InterfacePtr<IMultiColumnTextFrame> mcf(frameRef.GetDataBase(), this->GetTextContentUID(frameRef), UseDefaultIID());
		ASSERT(mcf);
		if (!mcf) {
			break;
		}
		
		WideString wstr = this->GetWideStringFromTextFrame(mcf);
		PMString str(wstr);
		//SNIPLOG("%s", str.GetPlatformString().c_str());
		//cout << "text in frame: " << str.GetPlatformString().c_str();
		
		// delete text frame
		InterfacePtr<ICommand> deleteCmd(CmdUtils::CreateCommand(kDeleteCmdBoss));
		ASSERT(deleteCmd);
		if (!deleteCmd) {
			break;
		}
		deleteCmd->SetItemList(UIDList(frameRef));
		CmdUtils::ProcessCommand(deleteCmd);
		//ASSERT_MSG(status == kSuccess, "kDeleteCmdBoss failed");
		
		result = wstr;
	} while(false);
	return result;
}
#endif
/*
 */
UID SnpCheckOutStory::GetTextContentUID(const UIDRef& graphicFrameUIDRef)
{
	UID result = kInvalidUID;
	InterfacePtr<IGraphicFrameData> graphicFrameData(graphicFrameUIDRef, UseDefaultIID());
	if (graphicFrameData) {
		result = graphicFrameData->GetTextContentUID();
	}
	return result;
}

/*
 */
WideString SnpCheckOutStory::GetWideStringFromTextFrame(IMultiColumnTextFrame* mcf)
{
	WideString result;
	do {
		InDesign::TextRange range = this->GetTextFrameTextRange(mcf);
		if (!range.IsValid()) {
			break;
		}
		SnpTextModelHelper textModelHelper;
		result = textModelHelper.GetWideStringFromTextRange(range);
	} while(false);
	return(result);
}


/*
 */
InDesign::TextRange SnpCheckOutStory::GetTextFrameTextRange(IMultiColumnTextFrame* mcf)
{
	InDesign::TextRange result;
	do {
		ASSERT(mcf);
		if (!mcf) {
			break;
		}
		
		// Make sure the text is composed.
		InterfacePtr<IFrameList> frameList(mcf->QueryFrameList());
		ASSERT(frameList);
		if (frameList == nil) {
			break;
		}
		const int32 kNoDamage = -1;
		if (frameList->GetFirstDamagedFrameIndex() != kNoDamage) {
			// Re-compose.
			mcf->RecomposeThru();
		}
		
		InterfacePtr<ITextModel> textModel(mcf->QueryTextModel());
		ASSERT(textModel);
		if (!textModel) {
			break;
		}
		
		// Check if the story contains any characters.
		// Note that when a story is created it has a terminating
		// character and length of 1 characters. We never
		// want to include the terminating character in our range.
		int32 charactersInPrimaryStoryThread = textModel->GetPrimaryStoryThreadSpan();
		// Number of characters in the story including the terminating character
		if (charactersInPrimaryStoryThread <= 1) {
			break; // the story has no significant characters
		}
		
		// Check if this text frame displays any characters.
		int32 span = mcf->TextSpan();
		if (span <= 0) {
			break; // the text frame is empty
		}
		
		// Get the range of characters displayed in the frame.
		TextIndex startIndex = mcf->TextStart();
		// Index into the text model of the first character in the frame.
		TextIndex finishIndex = startIndex + span;
		// Index into the text model of the last character in the frame.
		
		// Check if this frame displays the story's terminating character.
		if (finishIndex >= charactersInPrimaryStoryThread)
		{
			// This frame contains the story's terminating character.
			// Exclude the terminating character from the range of
			// characters described by the text focus being created.
			span--;
			finishIndex--;
		}
		
		// Don't make a text focus if the frame only displays
		// the story's terminating character.
		if (span <= 0) {
			break;
		}
		
		result = InDesign::TextRange(textModel, startIndex, span, RangeData::kLeanForward);
	} while(false);
	return result;
}

/*
 */
bool16 SnpCheckOutStory::IsTextFrame(const UIDRef& graphicFrameUIDRef)
{
	bool16 result = kFalse;
	Utils<IPageItemTypeUtils> pageItemTypeUtils;
	if (pageItemTypeUtils && pageItemTypeUtils->IsTextFrame(graphicFrameUIDRef)) {
		result = kTrue;
	}
	return result;
}


	
ErrorCode SnpCheckOutStory::ImportICMLFileToStory(ILayoutControlData* layoutControlData, const IDFile& icmlFile, UIDRef& destStory) {
	ErrorCode result = kFailure;
	SDKLayoutHelper layoutHelper;
	do {
		
		// Parent the frame on the active spread layer.
		InterfacePtr<IHierarchy> activeSpreadLayerHierarchy(layoutControlData->QueryActiveLayer());
		ASSERT(activeSpreadLayerHierarchy != nil);
		if (activeSpreadLayerHierarchy == nil) {
			break;
		}
		UIDRef parentUIDRef = ::GetUIDRef(activeSpreadLayerHierarchy);
		
		// Transform the bounds of the frame from page co-ordinates
		// into the parent co-ordinates, i.e. the spread.
		ASSERT(layoutControlData->GetPage() != kInvalidUID);
		if (layoutControlData->GetPage() == kInvalidUID) {
			break;
		}
		UIDRef pageUIDRef(parentUIDRef.GetDataBase(), layoutControlData->GetPage());
		PMRect boundsInPageCoords(0,0,2000,2000); // hard wire for now.
		PMRect boundsInParentCoords = layoutHelper.PageToSpread(pageUIDRef, boundsInPageCoords);
		
		UIDRef frameRef = layoutHelper.PlaceFileInFrame(icmlFile,
														parentUIDRef,
														boundsInParentCoords,
														kMinimalUI, 
														TRUE,
														TRUE, 
														FALSE);
		
		// TODO add code that looks at SDKFilePlaceChooser::GetReplaceSelectedItem
		// and replaces the content of the frame indicated by selectedItemRef.
		
		InterfacePtr<IMultiColumnTextFrame> mcf(frameRef.GetDataBase(), this->GetTextContentUID(frameRef), UseDefaultIID());
		ASSERT(mcf);
		if (!mcf) {
			break;
		}
		
		InterfacePtr<ITextModel> textModel(mcf->QueryTextModel());
		ASSERT(textModel);
		if (!textModel) {
			break;
		}
		
		UIDRef sourceStory = ::GetUIDRef(textModel);
		//UIDRef sourceFrameRef = layoutHelper.GetGraphicFrameRef(textFrameColumn);	
		//UIDRef destStory;
		//instance.CreateTextFrame(sourceFrameRef, destStory);
		// Copy all of the text into the story associated with the new text frame.	
		result = this->CopyAll(sourceStory, destStory);
		
		// delete text frame
		InterfacePtr<ICommand> deleteCmd(CmdUtils::CreateCommand(kDeleteCmdBoss));
		ASSERT(deleteCmd);
		if (!deleteCmd) {
			break;
		}
		deleteCmd->SetItemList(UIDList(frameRef));
		CmdUtils::ProcessCommand(deleteCmd);
		//ASSERT_MSG(status == kSuccess, "kDeleteCmdBoss failed");
		
	} while(false);
	return result;
}

ErrorCode SnpCheckOutStory::PutICMLFileToStory(const IDFile& icmlFile, UIDRef& destStory) {
	ErrorCode result = kFailure;
	SDKLayoutHelper layoutHelper;
	do {
		
		IDocument *docFrom = Utils<ILayoutUIUtils>()->GetFrontDocument(); 
		if (docFrom == NULL ) {
			cout << "docFrom == NULL" << endl;
			break;
		}
		
		UIDRef docRef = GetUIDRef(docFrom);
		UIDRef storyUIDRef;
		
		InterfacePtr<ISpreadList> spreadList(docRef, UseDefaultIID());
		if(!spreadList) {
			break;
		}
		
		UIDRef spreadRef = UIDRef(docRef.GetDataBase(), spreadList->GetNthSpreadUID(0));
		
		UIDRef parentUIDRef = layoutHelper.GetActiveSpreadLayerRef(spreadRef);
		
		PMRect boundsInParentCoords(0,0,2000,2000); // hard wire for now.
		
		UIDRef frameRef = layoutHelper.PlaceFileInFrame(icmlFile,
														parentUIDRef,
														boundsInParentCoords,
														kMinimalUI, 
														TRUE,
														TRUE, 
														FALSE);
		
		if(frameRef == UIDRef::gNull)
			break;
		// TODO add code that looks at SDKFilePlaceChooser::GetReplaceSelectedItem
		// and replaces the content of the frame indicated by selectedItemRef.
		
		InterfacePtr<IMultiColumnTextFrame> mcf(frameRef.GetDataBase(), this->GetTextContentUID(frameRef), UseDefaultIID());
		ASSERT(mcf);
		if (!mcf) {
			break;
		}
		
		InterfacePtr<ITextModel> textModel(mcf->QueryTextModel());
		ASSERT(textModel);
		if (!textModel) {
			break;
		}
		
		UIDRef sourceStory = ::GetUIDRef(textModel);
		//UIDRef sourceFrameRef = layoutHelper.GetGraphicFrameRef(textFrameColumn);	
		//UIDRef destStory;
		//instance.CreateTextFrame(sourceFrameRef, destStory);
		// Copy all of the text into the story associated with the new text frame.	
		result = this->CopyAll(sourceStory, destStory);
		
		// delete text frame
		InterfacePtr<ICommand> deleteCmd(CmdUtils::CreateCommand(kDeleteCmdBoss));
		ASSERT(deleteCmd);
		if (!deleteCmd) {
			break;
		}
		deleteCmd->SetItemList(UIDList(frameRef));
		CmdUtils::ProcessCommand(deleteCmd);
		//ASSERT_MSG(status == kSuccess, "kDeleteCmdBoss failed");
		
	} while(false);
	return result;
}

ErrorCode SnpCheckOutStory::ReplaceStoryByICMLs(string _attribute, string storyID, string storySessionID) {
	// Get the list of stories in this document
	ErrorCode result = kFailure;
	IDocument* iDocument = Utils<ILayoutUIUtils>()->GetFrontDocument();
	
	do {
		InterfacePtr<IStoryList> storyList(iDocument, UseDefaultIID());
		ASSERT(storyList);
		if (!storyList) {
			break;
		}
		
		int textModelCount = storyList->GetAllTextModelCount();
		for (int32 ii = 0; ii < textModelCount; ii++ )
		{
			cout << "--++--story: " << ii << endl;
			TextStory_StoryAccess storyAccess = storyList->GetNthTextModelAccess(ii);
			
			// Get the text model of the story.
			UIDRef storyUIDRef = storyList->GetNthTextModelUID(ii);
			InterfacePtr<ITextModel> textModel(storyUIDRef, UseDefaultIID());
			ASSERT(textModel);
			if (!textModel) {
				break;
			}
			
			// get storyID
			//UIDRef storyUIDRef = ::GetUIDRef(textModel);
			InterfacePtr<IIDMLComponentName> compName(storyUIDRef, UseDefaultIID());
			WideString nameStr;
			compName->Get(nameStr);
			string compNameStr;
			StringUtils::ConvertWideStringToUTF8(nameStr, compNameStr);
			
			// get index of story in g_TextFrames
			int storyIndex = 0;
			for (int i = 0; i < g_TextFrameCount; i++) {
				if (storyID.compare(g_TextFrames[i].storyID)==0) {
					if ((compNameStr.compare(g_TextFrames[i].textframeUID) == 0)&&(_attribute.compare(g_TextFrames[i].attribute) != 0)) {
						cout << "this texframe need to importing:" << i << endl;
						// lock the selected text frame
						g_TextFrames[storyIndex].isLocked = TRUE;
						
						// assign story session id
						g_TextFrames[storyIndex].sessionID = storySessionID;

						storyIndex = i;
						string checkpath = g_System_WorkspaceDir + "/" + storyID + "_" + g_TextFrames[i].attribute + ".icml";
						FILE *fn = fopen(checkpath.c_str(), "r");
						if (fn == NULL) {
							cout << "cannot find path:" << checkpath << endl;
							fclose(fn);
							continue;
						}
						fclose(fn);
						// import content from icml
						string ICMLImport = g_SDK_WorkspaceDir + ":" + storyID + "_" + g_TextFrames[i].attribute + ".icml";
						cout << ">>ICMLImport: " << ICMLImport << endl;
						PMString fileLocation(ICMLImport.c_str());
						IDFile importFile(fileLocation);
						
						// get length of current text model
						int l = textModel->TotalLength();
						// remove content of selected text frame
						SnpTextModelHelper	textCmdHelper;
						textCmdHelper.DeleteText(textModel, 0, l-1);
						cout << "finsihed delete text in frame" << endl;
						/*
						if(Utils<ISelectionUtils>() == nil) {
							cout << "couldn't find active textframe" << endl;
							break;
						}
						InterfacePtr<ISelectionManager> selectionManager(Utils<ISelectionUtils>()->QueryActiveSelection());
						if (!selectionManager) {
							break;
						}
						selectionManager->DeselectAll(nil);
						
						// Use to point move to textframe
						// Make a text selection to set the text caret blinking at the start of the story.
						InterfacePtr<ITextSelectionSuite> textSelectionSuite(selectionManager, UseDefaultIID());
						if (!textSelectionSuite) {
							break;
						}
						textSelectionSuite->SetTextSelection(storyUIDRef, RangeData(0, RangeData::kLeanForward), Selection::kScrollIntoView, nil); // scrollTo
						cout << "SetTextSelection 1" << endl;
						
						InterfacePtr<IActiveContext> iActiveContext(GetExecutionContextSession()->GetActiveContext());
						if( !iActiveContext )              
							break;
						
						InterfacePtr<ILayoutControlData> layoutControlData(iActiveContext->GetContextView(), UseDefaultIID());
						if (!layoutControlData) {
							break;
						}
						
						ImportICMLFileToStory(layoutControlData, importFile, storyUIDRef);
						 */
						PutICMLFileToStory(importFile, storyUIDRef);
						cout << "ImportICMLFileToStory 2" << endl;
						//return kSuccess;
					}
				}
			}
		}
		cout << "return success" << endl;
		return kSuccess;
	}while(kFalse);
	cout << "return failed" << endl;
	return result;
}

/*
 */
ErrorCode SnpCheckOutStory::CopyAll(const UIDRef& sourceStory, const UIDRef& destStory)	
{
	ErrorCode status = kFailure;
	do {
		InterfacePtr<ITextModel> sourceTextModel(sourceStory, UseDefaultIID());
		if (sourceTextModel == nil) {
			ASSERT_FAIL("sourceTextModel invalid");
			break;
		}
		InterfacePtr<ITextModel> destTextModel(destStory, UseDefaultIID());
		if (destTextModel == nil) {
			ASSERT_FAIL("destTextModel invalid");
			break;
		}
		status = this->ProcessCopyStoryRangeCmd
												(
													sourceStory,
													0,
													sourceTextModel->GetPrimaryStoryThreadSpan()-1,
													destStory,
													0, // Insert the copied text at the start of the destination story.
													0
												);
	} while (false);
	return status;
}


/*
 */
ErrorCode SnpCheckOutStory::ProcessCopyStoryRangeCmd
(
 const UIDRef& sourceStory, 
 TextIndex sourceStart, 
 int32 sourceLength, 
 const UIDRef& destStory,
 TextIndex destStart, 
 int32 destLength
)
{
	SnpTextModelHelper	textCmdHelper;
	return textCmdHelper.ProcessCopyStoryRangeCmd(sourceStory, sourceStart, sourceLength, destStory, destStart, destLength);
}



// --------------------------------- SnippetRunner framework hooks ---------------------------------------------------

class _SnpRunnerCheckOutStory : public SnpRunnable
	{
		
	public:
		// SnippetRunner framework hooks.
		
		/** Constructor.
		 */
		_SnpRunnerCheckOutStory();
		
		/** Destructor
		 */
		virtual ~_SnpRunnerCheckOutStory();
		
		/** Return kTrue if the snippet can run.
		 @param runnableContext see ISnpRunnableContext for documentation.
		 @return kTrue if a document is open, kFalse otherwise
		 */
		bool16			CanRun(ISnpRunnableContext* runnableContext);
		
		/** Run the snippet.
		 @param runnableContext see ISnpRunnableContext for documentation.
		 @return kSuccess on success, other ErrorCode otherwise.
		 */
		ErrorCode		Run(ISnpRunnableContext* runnableContext);
		
		/**	Don't present this snippet in the framework's UI if the
		 product we are running under is InCopy.
		 @return kTrue if the snippet can be loaded, kFalse otherwise.
		 */
		bool16 CanLoad() const;
		
		
		/** 
		 get the snippet context
		 @return eSnpRunContextType for this snippet
		 */
		virtual ISnipRunSuite::eSnpRunContextType GetContext(void){return ISnipRunSuite::kSnpRunLayoutTargetContext;}
	};

/* Constructor
 */
_SnpRunnerCheckOutStory::_SnpRunnerCheckOutStory() : SnpRunnable("CheckOutStory")
{
	this->SetDescription("check out the selected story from CMS");
	this->SetPreconditions("text frame selected");
	this->SetCategories("sdk_snippet, sdk_text");
}

/* Destructor
 */
_SnpRunnerCheckOutStory::~_SnpRunnerCheckOutStory()
{
}

/*
 */
bool16 _SnpRunnerCheckOutStory::CanRun(ISnpRunnableContext* runnableContext)
{
	bool16 result = kFalse;
	do {
		InterfacePtr<ITextTarget> textTarget(runnableContext, UseDefaultIID());
		if (textTarget == nil) {
			break;
		}
		
		InterfacePtr<ITextModel> textModel(textTarget->QueryTextModel());
		ASSERT(textModel);
		if (textModel == nil) {
			cout << "textModel == nil" << endl;
			break;
		}		
		result = kTrue;
	} while(false);
	return result;
}

/*
 */
/*
ErrorCode _SnpRunnerCheckOutStory::Run(ISnpRunnableContext* runnableContext)		//<--20121210 attribute
{
	
	//printf("this is _SnpRunnerCheckInStory::Run \n");
	
	ErrorCode status = kFailure;
	//RangeProgressBar progbar("Please wait...", 0, 100, kTrue, kFalse, nil, kFalse);
	
	do {
		cout << "run check out story snippet" << endl;
		
		SnpCheckOutStory instance;
		
		// Find the selected text model
		InterfacePtr<ITextTarget> textTarget(runnableContext, UseDefaultIID());
		if (textTarget == nil) {
			cout << "textTarget is nil" << endl;
			break;
		}
		InterfacePtr<ITextModel> textModel(textTarget->QueryTextModel());
		ASSERT(textModel);
		if (textModel == nil) {
			cout << "textModel == nil" << endl;
			break;
		}		
		
		// get storyID
		UIDRef storyUIDRef = ::GetUIDRef(textModel);
		InterfacePtr<IIDMLComponentName> compName(storyUIDRef, UseDefaultIID());
		WideString nameStr;
		compName->Get(nameStr);
		string compNameStr;
		StringUtils::ConvertWideStringToUTF8(nameStr, compNameStr);
		
		// get index of story in g_TextFrames
		int storyIndex = 0;
		string storyID = "";
		string attribute = "";
		for (int i = 0; i < g_TextFrameCount; i++) {
			if (compNameStr.compare(g_TextFrames[i].textframeUID) == 0) {
				
				// get storyID from g_TextFramesID[i]
				storyID = g_TextFrames[i].storyID;
				attribute = g_TextFrames[i].attribute;
				cout << "storyID: " << storyID << endl;
				//g_TextFrames[i].isLocked = TRUE;
				storyIndex = i;
				break;
			}
		}
		
		if (storyID.length() < 1) { // can't get storyID, so break
			//CAlert::InformationAlert("Cannot check out story content from CMS. Please try again");
			AMPCAlert::ModalAlert
			(
			 "Audience Media InDesign Plug-in\n\nCannot check out story content from CMS\n\nPlease try again",	// Alert string
			 kOKString, 					// OK button
			 kNullString, 					// No second button
			 kNullString, 					// No third button
			 kNoNeedToWaitForDialog,		// Set OK button to default
			 CAlert::eNoIcon				// No icon.
			 );
			
			break;	
		}
		
		
		// download icml file from CMS
		string error;
		string storySessionID;
		//int requestResult = HTTPRequestHelper::GetStoryContentFromCMS(storyID, error, storySessionID);
		int requestResult = HTTPRequestHelper::GetStoryContentFromCMS(g_Issueid, storyID, error, storySessionID);
		if (requestResult == FALSE) {
			// cannot download icml file, so break
#if _INDESIG_DEBUG
			//CAlert::InformationAlert(PMString(error.c_str()));
			AMPCAlert::ModalAlert
			(
			 PMString(error.c_str()),	// Alert string
			 kOKString, 					// OK button
			 kNullString, 					// No second button
			 kNullString, 					// No third button
			 kNoNeedToWaitForDialog,		// Set OK button to default
			 CAlert::eNoIcon				// No icon.
			 );
#else
			//CAlert::InformationAlert("Cannot check out story content from CMS. Please try again");
			string _logging = "Cannot check out story content from CMS (issue - story id): " + g_Issueid + " - " + storyID;
			SaveLogCenterData(_logging);
			AMPCAlert::ModalAlert
			(
			 "Audience Media InDesign Plug-in\n\nCannot check out story content from CMS\n\nPlease try again",	// Alert string
			 kOKString, 					// OK button
			 kNullString, 					// No second button
			 kNullString, 					// No third button
			 kNoNeedToWaitForDialog,		// Set OK button to default
			 CAlert::eNoIcon				// No icon.
			 );
#endif
			
			break;
		}
		
		// lock the selected text frame
		g_TextFrames[storyIndex].isLocked = TRUE;
		
		// assign story session id
		g_TextFrames[storyIndex].sessionID = storySessionID;
		//cout << "checked out story session: " << g_TextFrames[storyIndex].sessionID << endl;
		
		// get length of current text model
		int l = textModel->TotalLength();
		// remove content of selected text frame
		SnpTextModelHelper	textCmdHelper;
		textCmdHelper.DeleteText(textModel, 0, l-1);
		
		// import content from icml
		string ICMLImport = g_SDK_WorkspaceDir + ":" + storyID + "_" + attribute + ".icml";		//<--attribute
		//string ICMLImport = "Macintosh HD:Projects:InDesign-Plugin:temp:b290d2bf019ab163f32223929ab90563.icml";
		cout << "+ICMLImport: " << ICMLImport << endl;
		PMString fileLocation(ICMLImport.c_str());
		IDFile importFile(fileLocation);
		
		//UIDRef docUIDRef = ::GetUIDRef(runnableContext->GetActiveContext()->GetContextDocument());
		//status = instance.ImportToSpreadElement(docUIDRef, importFile);
		
		InterfacePtr<ILayoutControlData> layoutControlData(runnableContext->GetActiveContext()->GetContextView(), UseDefaultIID());
		if (!layoutControlData) {
			break;
		}
		//WideString icmlContent = instance.textInImportedFile(layoutControlData, importFile);
		//PMString str(icmlContent);
		//cout << "icmlContent: " << str.GetPlatformString().c_str();
		
		UIDRef destStory = ::GetUIDRef(textModel);
		status = instance.ImportICMLFileToStory(layoutControlData, importFile, destStory);
		
		//boost::shared_ptr<WideString>	wide(new WideString(icmlContent));
		//textCmdHelper.InsertText(textModel, 0, wide);		
		//textCmdHelper.ReplaceText(textModel, 0, l-1, wide);
		// import all icml on same story id
		status = instance.ReplaceStoryByICMLs(attribute, storyID, storySessionID);
		AMPUtils::StoryInfoHiddenSetting();		//<--save info checked out
 
		status = kSuccess;
		string _logging = "Checked out story:" + storyID + ".icml";
		SaveLogCenterData(_logging);
	} while(false);
	return status;
}
*/
ErrorCode _SnpRunnerCheckOutStory::Run(ISnpRunnableContext* runnableContext)
{
	
	//printf("this is _SnpRunnerCheckInStory::Run \n");
	
	ErrorCode status = kFailure;
	//RangeProgressBar progbar("Please wait...", 0, 100, kTrue, kFalse, nil, kFalse);
	
	do {
		//cout << "run check out story snippet" << endl;
		
		SnpCheckOutStory instance;
		
		// Find the selected text model
		InterfacePtr<ITextTarget> textTarget(runnableContext, UseDefaultIID());
		if (textTarget == nil) {
			cout << "textTarget is nil" << endl;
			break;
		}
		InterfacePtr<ITextModel> textModel(textTarget->QueryTextModel());
		ASSERT(textModel);
		if (textModel == nil) {
			cout << "textModel == nil" << endl;
			break;
		}		
		
		// get storyID
		UIDRef storyUIDRef = ::GetUIDRef(textModel);
		InterfacePtr<IIDMLComponentName> compName(storyUIDRef, UseDefaultIID());
		WideString nameStr;
		compName->Get(nameStr);
		string compNameStr;
		StringUtils::ConvertWideStringToUTF8(nameStr, compNameStr);
		
		// get index of story in g_TextFrames
		int storyIndex = 0;
		string storyID = "";
		if (g_TextFrames == NULL) {
			break;
		}
		for (int i = 0; i < g_TextFrameCount; i++) {
			if (compNameStr.compare(g_TextFrames[i].textframeUID) == 0) {
				
				// get storyID from g_TextFramesID[i]
				storyID = g_TextFrames[i].storyID;
				//cout << "storyID: " << storyID << endl;
				//g_TextFrames[i].isLocked = TRUE;
				storyIndex = i;
				break;
			}
		}
		
		if (storyID.length() < 1) { // can't get storyID, so break
			//CAlert::InformationAlert("Cannot check out story content from CMS. Please try again");
			AMPCAlert::ModalAlert
			(
			 "\n\nCheck-out Failed. Please try again.",	// Alert string
			 "OK",							// OK button
			 kNullString, 					// No second button
			 kNullString, 					// No third button
			 kNoNeedToWaitForDialog,		// Set OK button to default
			 1								// No icon.
			 );
			
			break;	
		}
			
		
		// download icml file from CMS
		string error;
		string storySessionID;
		//int requestResult = HTTPRequestHelper::GetStoryContentFromCMS(storyID, error, storySessionID);
		int requestResult = HTTPRequestHelper::GetStoryContentFromCMS(g_Issueid, storyID, error, storySessionID);
		if (requestResult == FALSE) {
			//CAlert::InformationAlert("Cannot check out story content from CMS. Please try again");
			string _logging = "Cannot check out story content from CMS (issue - story id): " + g_Issueid + " - " + storyID;
			SaveLogCenterData(_logging);
			AMPCAlert::ModalAlert
			(
			 PMString(error.c_str()),		//"Audience Media InDesign Plug-in\n\nCannot check out story content from CMS\n\nPlease try again",	// Alert string
			 "OK",							// OK button
			 kNullString, 					// No second button
			 kNullString, 					// No third button
			 kNoNeedToWaitForDialog,		// Set OK button to default
			 1								// No icon.
			 );
			
			break;
		}

		// lock the selected text frame
		g_TextFrames[storyIndex].isLocked = TRUE;
		
		// assign story session id
		g_TextFrames[storyIndex].sessionID = storySessionID;
		//cout << "checked out story session: " << g_TextFrames[storyIndex].sessionID << endl;
		
		// get length of current text model
		int l = textModel->TotalLength();
		// remove content of selected text frame
		SnpTextModelHelper	textCmdHelper;
		textCmdHelper.DeleteText(textModel, 0, l-1);
		
		// import content from icml
		string ICMLImport = g_SDK_WorkspaceDir + ":" + storyID + ".icml";
		//string ICMLImport = "Macintosh HD:Projects:InDesign-Plugin:temp:b290d2bf019ab163f32223929ab90563.icml";
		//cout << "ICMLImport: " << ICMLImport << endl;
		PMString fileLocation(ICMLImport.c_str());
		IDFile importFile(fileLocation);
		
		//UIDRef docUIDRef = ::GetUIDRef(runnableContext->GetActiveContext()->GetContextDocument());
		//status = instance.ImportToSpreadElement(docUIDRef, importFile);
		
		InterfacePtr<ILayoutControlData> layoutControlData(runnableContext->GetActiveContext()->GetContextView(), UseDefaultIID());
		if (!layoutControlData) {
			break;
		}
		//WideString icmlContent = instance.textInImportedFile(layoutControlData, importFile);
		//PMString str(icmlContent);
		//cout << "icmlContent: " << str.GetPlatformString().c_str();
		
		UIDRef destStory = ::GetUIDRef(textModel);
		status = instance.ImportICMLFileToStory(layoutControlData, importFile, destStory);
		
		//boost::shared_ptr<WideString>	wide(new WideString(icmlContent));
		//textCmdHelper.InsertText(textModel, 0, wide);		
		//textCmdHelper.ReplaceText(textModel, 0, l-1, wide);
		UIDRef frameUIDref = UIDRef::gNull;
		for (int i = 0; i < g_assignmentPtr.size(); i++) {
			if(storyUIDRef == g_assignmentPtr[i].story_assignment){
				g_assignmentPtr[i]._status = GRAPHICFRAME_LOCKED;
				frameUIDref =  g_assignmentPtr[i].frameUIDRef;
				break;
			}
		}
		AMPUtils::UpdateStatusProperties(frameUIDref, GRAPHICFRAME_EDITING);
		status = kSuccess;
		string _logging = "Checked out story:" + storyID + ".icml";
		SaveLogCenterData(_logging);
	} while(false);
	return status;
}

/*
 */
bool16  _SnpRunnerCheckOutStory::CanLoad() const
{
	bool16 result = kTrue;
	if (LocaleSetting::GetLocale().IsProductFS(kInCopyProductFS)) {
		// Text frames can be manipulated under InCopy
		// but we don't load this snippet because there's no pointer tool
		// to select a text frame with. If we loaded the Go button for the
		// snippet would pretty much always be disabled.
		result = kFalse;
	}
	return result;
}

/*	Declare an instance to register the snippet with the framework.
 */
static _SnpRunnerCheckOutStory instance_SnpRunnerCheckOutStory;
DEFINE_SNIPPET(_SnpRunnerCheckOutStory)

//End, SnpCheckInStory.cpp
